﻿// Decompiled with JetBrains decompiler
// Type: Microsoft.InfoCards.StoreConnection
// Assembly: infocard, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// MVID: 8E14765A-6610-409A-BA36-099A0642905D
// Assembly location: E:\git\ALLIDA\windll\infocard.exe

using Microsoft.InfoCards.Diagnostics;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Security.Principal;

namespace Microsoft.InfoCards
{
  internal class StoreConnection : IDisposable
  {
    private static Hashtable s_instanceCache = CollectionsUtil.CreateCaseInsensitiveHashtable();
    public const string DEFAULTFILENAME = "CardSpace.db";
    public const string STOREFILENAMEV2 = "CardSpaceSP2.db";
    public const string STORAGEPATH = "Microsoft\\CardSpace\\";
    private string m_path;
    private int m_refCount;
    private Hashtable m_sources;
    private string m_instanceId;
    private string m_activeSource;
    private string m_localSource;
    private bool m_isLoaded;
    private WindowsIdentity m_identity;
    private bool m_disposed;
    private object m_sync;

    protected StoreConnection(WindowsIdentity identity)
    {
      this.m_identity = new WindowsIdentity(identity.Token);
      this.m_instanceId = this.m_identity.User.Value;
      this.m_sync = new object();
      this.m_disposed = false;
      this.m_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft\\CardSpace\\");
      this.m_localSource = this.m_path + "CardSpaceSP2.db";
      this.m_activeSource = this.m_localSource;
      this.m_sources = CollectionsUtil.CreateCaseInsensitiveHashtable();
    }

    public Hashtable DataSources
    {
      get
      {
        return this.m_sources;
      }
    }

    public string ActiveDataSource
    {
      get
      {
        return this.m_activeSource;
      }
    }

    public string LocalDataSource
    {
      get
      {
        return this.m_localSource;
      }
    }

    public string InstanceId
    {
      get
      {
        return this.m_instanceId;
      }
    }

    public WindowsIdentity Identity
    {
      get
      {
        return this.m_identity;
      }
    }

    protected int ReferenceCount
    {
      get
      {
        return this.m_refCount;
      }
      set
      {
        this.m_refCount = value;
      }
    }

    public static StoreConnection CreateConnection()
    {
      WindowsIdentity current = WindowsIdentity.GetCurrent();
      InfoCardTrace.Assert(!current.IsSystem, "Identity should not be LSA");
      return StoreConnection.GetConnection(current, true);
    }

    public static StoreConnection GetConnection()
    {
      WindowsIdentity current = WindowsIdentity.GetCurrent();
      InfoCardTrace.Assert(!current.IsSystem, "Identity should not be LSA");
      return StoreConnection.GetConnection(current);
    }

    public static StoreConnection GetConnection(WindowsIdentity identity)
    {
      return StoreConnection.GetConnection(identity, false);
    }

    private static StoreConnection GetConnection(
      WindowsIdentity identity,
      bool allowCreate)
    {
      StoreConnection storeConnection = (StoreConnection) null;
      lock (StoreConnection.s_instanceCache.SyncRoot)
      {
        storeConnection = (StoreConnection) StoreConnection.s_instanceCache[(object) identity.User.Value];
        if (storeConnection == null)
        {
          if (!allowCreate)
            throw InfoCardTrace.ThrowHelperError((Exception) new DataAccessException(SR.GetString("StoreFailedToOpenStore")));
          storeConnection = new StoreConnection(identity);
          storeConnection.Load();
          StoreConnection.s_instanceCache[(object) identity.User.Value] = (object) storeConnection;
        }
        else if (!storeConnection.m_isLoaded)
          storeConnection.Load();
        ++storeConnection.ReferenceCount;
      }
      return storeConnection;
    }

    public void SetActiveDataSource(string id)
    {
      this.ThrowIfNotLoaded();
      if (!this.m_sources.ContainsKey((object) id))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentOutOfRangeException(nameof (id), (object) id, SR.GetString("StoreSourceIdOutOfRange")));
      if (((DataSource) this.m_sources[(object) this.m_activeSource]).IsProcessingTransaction())
        throw InfoCardTrace.ThrowHelperError((Exception) new InvalidOperationException(SR.GetString("StoreProcessingTransaction")));
      this.m_activeSource = id;
    }

    public void Close()
    {
      this.ThrowIfNotLoaded();
      lock (StoreConnection.s_instanceCache.SyncRoot)
      {
        --this.ReferenceCount;
        if (this.ReferenceCount != 0)
          return;
        StoreConnection.s_instanceCache.Remove((object) this.m_identity.User.Value);
        this.m_isLoaded = false;
        foreach (string key in (IEnumerable) this.m_sources.Keys)
          ((DataSource) this.m_sources[(object) key]).Close();
        this.m_sources.Clear();
      }
    }

    void IDisposable.Dispose()
    {
      lock (this.m_sync)
      {
        if (this.m_disposed)
          return;
        this.m_disposed = true;
        if (this.m_identity == null)
          return;
        this.m_identity.Dispose();
        this.m_identity = (WindowsIdentity) null;
      }
    }

    public bool IsDataSourceCleared(string sourceId)
    {
      if (!this.m_sources.ContainsKey((object) sourceId))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentOutOfRangeException(nameof (sourceId), (object) sourceId, SR.GetString("StoreSourceIdOutOfRange")));
      return ((DataSource) this.m_sources[(object) sourceId]).IsCleared;
    }

    public void ResetDataSourceClearedFlag(string sourceId)
    {
      if (!this.m_sources.ContainsKey((object) sourceId))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentOutOfRangeException(nameof (sourceId), (object) sourceId, SR.GetString("StoreSourceIdOutOfRange")));
      ((DataSource) this.m_sources[(object) sourceId]).IsCleared = false;
    }

    public DataRow GetSingleRow(QueryDetails details, params QueryParameter[] objectQuery)
    {
      return this.GetSingleRow(details, this.m_activeSource, objectQuery);
    }

    public DataRow GetSingleRow(params QueryParameter[] objectQuery)
    {
      return this.GetSingleRow(this.m_activeSource, objectQuery);
    }

    public DataRow GetSingleRow(string sourceId, params QueryParameter[] objectQuery)
    {
      return this.GetSingleRow(QueryDetails.FullRow, sourceId, objectQuery);
    }

    public DataRow GetSingleRow(
      QueryDetails details,
      string sourceId,
      params QueryParameter[] objectQuery)
    {
      this.ThrowIfNotLoaded();
      if (objectQuery == null || objectQuery.Length == 0)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (objectQuery));
      if (!this.m_sources.ContainsKey((object) sourceId))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentOutOfRangeException(nameof (sourceId), (object) sourceId, SR.GetString("StoreSourceIdOutOfRange")));
      return ((DataSource) this.m_sources[(object) sourceId]).GetSingleRow(details, objectQuery);
    }

    public ICollection<DataRow> Query(
      QueryDetails details,
      params QueryParameter[] query)
    {
      return this.Query(details, this.m_activeSource, query);
    }

    public ICollection<DataRow> Query(params QueryParameter[] query)
    {
      return this.Query(this.m_activeSource, query);
    }

    public ICollection<DataRow> Query(
      string sourceId,
      params QueryParameter[] query)
    {
      return this.Query(QueryDetails.FullRow, sourceId, query);
    }

    public ICollection<DataRow> Query(
      QueryDetails details,
      string sourceId,
      params QueryParameter[] query)
    {
      this.ThrowIfNotLoaded();
      if (query == null || query.Length == 0)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (query));
      if (!this.m_sources.ContainsKey((object) sourceId))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentOutOfRangeException(nameof (sourceId), (object) sourceId, SR.GetString("StoreSourceIdOutOfRange")));
      return (ICollection<DataRow>) ((DataSource) this.m_sources[(object) sourceId]).Query(details, query);
    }

    public void Save(string sourceId, DataRow row)
    {
      this.ThrowIfNotLoaded();
      if (row == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (row));
      if (!this.m_sources.ContainsKey((object) sourceId))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentOutOfRangeException(nameof (sourceId), (object) sourceId, SR.GetString("StoreSourceIdOutOfRange")));
      ((DataSource) this.m_sources[(object) sourceId]).Save(row);
    }

    public void Save(DataRow row)
    {
      this.ThrowIfNotLoaded();
      if (row == null)
        throw InfoCardTrace.ThrowHelperArgumentNull(nameof (row));
      if (!string.IsNullOrEmpty(row.SourceId))
        this.Save(row.SourceId, row);
      else
        this.Save(this.m_activeSource, row);
    }

    public void Delete(string sourceId, DataRow row)
    {
      this.ThrowIfNotLoaded();
      if (row.InstanceId != this.m_instanceId)
        throw InfoCardTrace.ThrowHelperError((Exception) new InvalidOperationException(SR.GetString("StoreRowOwnedByOtherDataSource")));
      if (!this.m_sources.ContainsKey((object) sourceId))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentOutOfRangeException(nameof (sourceId), (object) sourceId, SR.GetString("StoreSourceIdOutOfRange")));
      ((DataSource) this.m_sources[(object) sourceId]).Delete(row);
    }

    public void Delete(DataRow row)
    {
      this.Delete(row.SourceId, row);
    }

    public void BeginTransaction()
    {
      this.BeginTransaction(this.m_activeSource);
    }

    public void BeginTransaction(string sourceId)
    {
      if (!this.m_sources.ContainsKey((object) sourceId))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentOutOfRangeException(" sourceId ", (object) sourceId, SR.GetString("StoreSourceIdOutOfRange")));
      ((DataSource) this.m_sources[(object) sourceId]).BeginTransaction();
    }

    public void CommitTransaction()
    {
      this.CommitTransaction(this.m_activeSource);
    }

    public void CommitTransaction(string sourceId)
    {
      if (!this.m_sources.ContainsKey((object) sourceId))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentOutOfRangeException(" sourceId ", (object) sourceId, SR.GetString("StoreSourceIdOutOfRange")));
      ((DataSource) this.m_sources[(object) sourceId]).CommitTransaction();
    }

    public void RollbackTransaction()
    {
      this.RollbackTransaction(this.m_activeSource);
    }

    public void RollbackTransaction(string sourceId)
    {
      if (!this.m_sources.ContainsKey((object) sourceId))
        throw InfoCardTrace.ThrowHelperError((Exception) new ArgumentOutOfRangeException(" sourceId ", (object) sourceId, SR.GetString("StoreSourceIdOutOfRange")));
      ((DataSource) this.m_sources[(object) sourceId]).RollbackTransaction();
    }

    protected virtual void CreateDefaultDataSources(Hashtable list)
    {
      string str = this.m_path + "CardSpace.db";
      using (new SystemIdentity(true))
      {
        if (File.Exists(this.m_localSource))
        {
          if (File.Exists(str))
          {
            if (DateTime.Compare(File.GetLastWriteTime(str), File.GetLastWriteTime(this.m_localSource)) > 0)
            {
              File.Delete(this.m_localSource);
              if (File.Exists(this.m_localSource + ".shadow"))
                File.Delete(this.m_localSource + ".shadow");
              this.AtomicFileCopy(str, this.m_localSource);
            }
          }
        }
        else if (!File.Exists(this.m_localSource) && File.Exists(this.m_localSource + ".shadow"))
        {
          FileInfo fileInfo = new FileInfo(this.m_localSource + ".shadow");
          if (0L == fileInfo.Length)
            fileInfo.Delete();
        }
        else if (File.Exists(str))
          this.AtomicFileCopy(str, this.m_localSource);
        else if (File.Exists(str + ".shadow"))
        {
          FileInfo fileInfo = new FileInfo(str + ".shadow");
          if (0L == fileInfo.Length)
            fileInfo.Delete();
          else
            this.AtomicFileCopy(str + ".shadow", this.m_localSource);
        }
      }
      list.Add((object) this.m_localSource, (object) new FileDataSource(this.m_identity, this.m_localSource, this.m_instanceId, SecondaryIndexDefinition.MasterIndexes));
    }

    protected void AtomicFileCopy(string source, string destination)
    {
      if (!File.Exists(source))
        return;
      File.Copy(source, source + ".atomic", true);
      FileInfo fileInfo = new FileInfo(source + ".atomic");
      if (fileInfo.Length == 0L)
        return;
      fileInfo.MoveTo(destination);
    }

    protected void Load()
    {
      InfoCardTrace.Assert(!this.m_isLoaded, "Store is already loaded");
      this.CreateDefaultDataSources(this.m_sources);
      foreach (string key in (IEnumerable) this.m_sources.Keys)
      {
        if (!((DataSource) this.m_sources[(object) key]).IsLoaded)
        {
          bool flag = false;
          try
          {
            ((DataSource) this.m_sources[(object) key]).Load();
            flag = true;
          }
          catch (CorruptStoreException ex)
          {
            ((DataSource) this.m_sources[(object) key]).Clear();
          }
          catch (InvalidStoreProtectionKeyException ex)
          {
            ((DataSource) this.m_sources[(object) key]).Clear();
          }
          if (!flag)
            ((DataSource) this.m_sources[(object) key]).Load();
        }
      }
      this.m_isLoaded = true;
    }

    protected void ThrowIfNotLoaded()
    {
      InfoCardTrace.Assert(this.m_isLoaded, "store is not loaded");
    }
  }
}
